package com.xxxy.filter;

import com.xxxy.component.UserToken;
import com.xxxy.exception.MyException;
import com.xxxy.util.BeanUtils;
import com.xxxy.util.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
public class TokenFilter extends BasicHttpAuthenticationFilter {

    /**
     * 在这里拦截所有请求
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

        if(isLoginAttempt(request, response)){
            //如果存在，则进入 executeLogin 方法执行登入，检查 token 是否正确
            try {
                return executeLogin(request, response);
            } catch (Exception e){
                //跳转到onAccessDenied中
                e.printStackTrace();
                request.setAttribute("msg", e.getMessage());
            }
            return false;
        }
        return false;
    }

    /**
     * 判断用户是否想要登入
     * 检测 header 里面是否包含 Token 字段
     */
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        HttpServletRequest req = (HttpServletRequest) request;
        String token = req.getHeader("Authorization");
        return token != null;
    }

    /**
     * token认证异常时重定向到未登录异常接口
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception{
        HttpServletRequest req = (HttpServletRequest) request;
        log.info(req.getRequestURI());
        log.info("------------认证失败-------------");
        String error = (String) request.getAttribute("msg");
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.sendRedirect("/error/unAuthentication?error=" + error);
        return false;
    }

    /**
     * 用户存在，执行登录认证
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        //从请求头中获取token
        String token = getAuthzHeader(request);
        //对token进行非空校验
        if (StringUtils.isEmpty(token)) {
            throw new MyException("token为空");
        }
        //将token封装为UserToken
        JwtUtils jwtUtils = BeanUtils.getBean(JwtUtils.class);
        UserToken userToken = new UserToken();
        String id = null;
        try {
            id = jwtUtils.getUserIdFromToken(token);
        } catch (Exception e) {
            throw new MyException("token无效");
        }
        if(jwtUtils.isTokenExpired(token)){
            throw new MyException("token过期");
        }
        if (id != null) {
            userToken.setId(id);
            //用Realm进行身份认证
            getSubject(request, response).login(userToken);
            //无异常则认证通过
            return true;
        }
        return false;
    }
}
